Expand description

Watto

Build Status codecov

Utilities for parsing and serializing Plain Old Data.

Pod

The API is primarily defined on the Pod trait, which can be implemented for #[repr(C)] types. It is then possible to get a reference to that Pod or a slice thereof directly from an underlying buffer. Similarly, the Pod can also be turned into its underlying buffer as well, for example to write it out into an output buffer.

Features

writer: Exports an additional Writer wrapping a std::io::Write which allows explicitly aligning the output buffer by adding padding bytes.

strings: Exports a StringTable for serializing and reading deduplicated strings.

End-to-End Example

use std::mem;
use std::io::Write;

use watto::Pod;

/// Our format looks like this:
/// * A header, containing the number of `A`s.
/// * An aligned slice of `A`s (length given by the header)
/// * An aligned slice of `B`s (length implicitly given by end of buffer)
#[repr(C)]
struct Header {
    version: u32,
    num_as: u32,
}
unsafe impl Pod for Header {}

#[repr(C)]
#[derive(Debug, PartialEq)]
struct A(u16);
unsafe impl Pod for A {}

#[repr(C)]
#[derive(Debug, PartialEq)]
struct B(u64);
unsafe impl Pod for B {}

// Writing into an output buffer:
let mut writer = watto::Writer::new(vec![]);

writer.write_all(Header { version: 1, num_as: 3 }.as_bytes()).unwrap();
writer.align_to(mem::align_of::<A>()).unwrap();
writer.write_all(&[A(1), A(2), A(3)].as_bytes()).unwrap();
writer.align_to(mem::align_of::<B>()).unwrap();
writer.write_all(&[B(4), B(5), B(6)].as_bytes()).unwrap();

let buffer = writer.into_inner();

// Reading from a buffer:
let buffer = &buffer;

let (header, buffer) = Header::ref_from_prefix(buffer).unwrap();
let (_, buffer) = watto::align_to(buffer, mem::align_of::<A>()).unwrap();
let (r#as, buffer) = A::slice_from_prefix(buffer, header.num_as as usize).unwrap();
let (_, buffer) = watto::align_to(buffer, mem::align_of::<B>()).unwrap();
let bs = B::slice_from_bytes(buffer).unwrap();

assert_eq!(header.num_as, 3);
assert_eq!(r#as, &[A(1), A(2), A(3)]);
assert_eq!(bs, &[B(4), B(5), B(6)]);

Alternatives

Watto is strongly inspired by zerocopy.

Differences between the two include:

  • zerocopy has two distinct traits for reading and writing bytes, watto only has one for both.
  • In zerocopy, reading a value requires wrapping it in LayoutVerified. In watto, types implementing Pod can be read directly.
  • watto includes a Writer that allows explicit alignment of output.
  • watto includes a StringTable for (de)serializing strings.
  • zerocopy includes endianness-aware integer types.

Why Watto?

Qui-Gon Jinn: I have… acquired a pod in a game of chance. The fastest ever built.

Watto: I hope you didn’t kill anyone I know for it.

Star Wars: Episode I - The Phantom Menace

License

Watto is licensed under the Apache-2.0 license.

Structs

A struct for storing strings without duplicates.

Writerwriter

A wrapper around Write that keeps track of the bytes written.

Enums

An error when trying to read a string from a serialized StringTable.

Traits

Plain Old Data

Functions

Splits the given bytes into padding and a slice that is properly aligned to align bytes.